#include "stdafx.h"

#pragma warning(disable:4996)

#include "Level.h"

#include "Player.h"

namespace ETM
{
	Level::Level()
	{

	}

	Level::Level(std::string path)
	{
		LoadFromFile(path);
	}

	Level::Level(unsigned int w, unsigned int h)
	{
		for(unsigned int y = 0; y < h; y++)
		{
			values.push_back(std::vector<Block>());

			for(unsigned int x = 0; x < w; x++)
			{
				Block block(Passable, 0);
				values[y].push_back(block);
			}
		}
	}

	void Level::Update(float delta)
	{
		CM.Update(player, delta);
	}

	void Level::Render(sf::RenderWindow& window)
	{
		sf::View view = window.GetView();
		sf::FloatRect screen = view.GetRect();
		screen.Left -= tileSize;
		screen.Top -= tileSize;

		int tilesetWidth = tileset.GetImage()->GetWidth();

		for(unsigned int x = 0; x < values[0].size(); x++)
		{
			for(unsigned int y = 0; y < values.size(); y++)
			{
				float xPos = (float)x * tileSize;
				float yPos = (float)y * tileSize;

				if(!screen.Contains(xPos, yPos))
					continue;

				sf::IntRect srcRect(Utils::GetSrcRect(tilesetWidth, tileSize, values[y][x].value));

				tileset.SetSubRect(srcRect);
				tileset.SetPosition(xPos, yPos);
				window.Draw(tileset);
			}
		}

		CM.Render(window);
	}

	void Level::LoadBinary(const std::string& path)
	{
		
	}

	void Level::LoadFromFile(const std::string& path)
	{
		//std::vector<std::string> lines;
		//std::ifstream ifs(path.c_str());
		//std::string temp;

		////Store all the lines in a vector
		//while(std::getline(ifs, temp))
		//{
		//	//Do not add empty lines
		//	if(temp != "")
		//		lines.push_back(temp);
		//}

		////Close the file stream
		//ifs.close();

		////Level data
		//int width = 0;
		//int height = 0;

		//for(unsigned int i = 0; i < lines.size(); i++)
		//{
		//	std::string line = lines[i];

		//	if(line == "[Game Tileset]")
		//	{
		//		tileset = sf::Sprite(*IM.GetResource(lines[i + 1]));
		//	}
		//	else if(line == "[Player Position]")
		//	{
		//		boost::tokenizer<> tok(lines[i + 1]);
		//		boost::tokenizer<>::iterator it = tok.begin();
		//		float x = boost::lexical_cast<float>(*it);
		//		it++;
		//		float y = boost::lexical_cast<float>(*it);

		//		player->SetPosition(x, y);
		//	}
		//	else if(line == "[Dimensions]")
		//	{
		//		boost::tokenizer<> tok(lines[i + 1]);
		//		boost::tokenizer<>::iterator it = tok.begin();
		//		width = boost::lexical_cast<int>(*it);
		//		it++;
		//		height = boost::lexical_cast<int>(*it);

		//		for(int y = 0; y < height; y++)
		//		{
		//			values.push_back(std::vector<Block>());
		//			for(int x = 0; x < width; x++)
		//			{
		//				values[y].push_back(Block());
		//			}
		//		}
		//	}
		//	else if(line == "[Collision]")
		//	{
		//		for(int y = 0; y < height; y++)
		//		{
		//			int j = 0;
		//			boost::tokenizer<> tok(lines[i + y + 1]);
		//			for(boost::tokenizer<>::iterator it = tok.begin(); it != tok.end(); it++)
		//			{
		//				CollisionType colType = CollisionType(boost::lexical_cast<int>(*it));
		//				values[y][j++].colType = colType;
		//			}
		//		}
		//	}
		//	else if(line == "[Values]")
		//	{
		//		for(int y = 0; y < height; y++)
		//		{
		//			int j = 0;
		//			boost::tokenizer<> tok(lines[i + y + 1]);
		//			for(boost::tokenizer<>::iterator it = tok.begin(); it != tok.end(); it++)
		//			{
		//				values[y][j++].value = boost::lexical_cast<int>(*it);
		//			}
		//		}
		//	}
		//	else if(line == "[Diamonds]")
		//	{
		//		int line = i;
		//		int count = boost::lexical_cast<int>(lines[line++]);

		//		boost::tokenizer<> tok(lines[line++]);
		//		for(boost::tokenizer<>::iterator it = tok.begin(); it != tok.end(); it++)
		//		{
		//			
		//		}
		//	}
		//}

		std::vector<std::string> lines;
		std::ifstream ifs(path.c_str());
		std::string temp;

		//Store all the lines in a vector
		while(std::getline(ifs, temp))
		{
			//Do not add empty lines
			if(temp != "")
				lines.push_back(temp);
		}

		//Close the file stream
		ifs.close();

		//Level data
		int width = 0;
		int height = 0;

		for(unsigned int i = 0; i < lines.size(); i++)
		{
			std::string line = lines[i];

			if(line == "[Game Tileset]")
			{
				tileset = sf::Sprite(*IM.GetResource(lines[i + 1]));
			}
			else if(line == "[Player Position]")
			{
				float x = 0;
				float y = 0;
				sscanf(lines[i + 1].c_str(), "%f,%f", &x, &y);
				player->SetPosition(x, y);
			}
			else if(line == "[Dimensions]")
			{
				sscanf(lines[i + 1].c_str(), "%d,%d", &width, &height);

				for(int y = 0; y < height; y++)
				{
					values.push_back(std::vector<Block>());
					for(int x = 0; x < width; x++)
					{
						values[y].push_back(Block());
					}
				}
			}
			else if(line == "[Collision]")
			{
				for(int y = 0; y < height; y++)
				{
					int j = 0;
					boost::tokenizer<> tok(lines[i + y + 1]);
					for(boost::tokenizer<>::iterator it = tok.begin(); it != tok.end(); it++)
					{
						CollisionType colType = CollisionType(boost::lexical_cast<int>(*it));
						values[y][j++].colType = colType;
					}
				}
			}
			else if(line == "[Values]")
			{
				for(int y = 0; y < height; y++)
				{
					int j = 0;
					boost::tokenizer<> tok(lines[i + y + 1]);
					for(boost::tokenizer<>::iterator it = tok.begin(); it != tok.end(); it++)
					{
						values[y][j++].value = boost::lexical_cast<int>(*it);
					}
				}
			}
			else if(line == "[Diamonds]")
			{
				std::vector<std::string> splitVec;
				boost::algorithm::split(splitVec, lines[i + 1], boost::algorithm::is_any_of(" "));
				for(unsigned int j = 0; j < splitVec.size(); j++)
				{
					int x = 0;
					int y = 0;
					sscanf(splitVec[j].c_str(), "%d,%d", &x, &y);
					CM.AddCollectable(new Diamond(x, y));
				}
			}
		}
	}

	void Level::Fill(CollisionType colType, int newVal)
	{
		for(unsigned int x = 0; x < values.size(); x++)
			for(unsigned int y = 0; y < values[0].size(); y++)
			{
				values[y][x].colType = colType;
				values[y][x].value = newVal;
			}
	}

	void Level::Replace(int oldVal, int newVal)
	{
		for(unsigned int x = 0; x < values.size(); x++)
			for(unsigned int y = 0; y < values[0].size(); y++)
			{
				if(values[y][x].value == oldVal)
					values[y][x].value = newVal;
			}
	}

	void Level::Swap(int x1, int y1, int x2, int y2)
	{
		Block block1 = values[y1][x1];

		values[y1][x1] = values[y2][x2];
		values[y2][x2] = block1;

		values[y1][x1].moved = true;
		values[y2][x2].moved = true;
	}

	void Level::ClampView(sf::View& view)
	{
		sf::FloatRect screen = view.GetRect();

		float width = (float)GetWidthInPixels();
		float height = (float)GetHeightInPixels();
		float screenWidth = width < 800 ? width : width - 800;
		float screenHeight = height < 600 ? height : height - 600;

		screen.Left = Utils::Clamp<float>(screen.Left, 0, screenWidth);
		screen.Top = Utils::Clamp<float>(screen.Top, 0, screenHeight);
		screen.Right = screen.Left + 800;
		screen.Bottom = screen.Top + 600;
		
		view.SetFromRect(screen);
	}

	int Level::GetWidth()
	{
		return values[0].size();
	}

	int Level::GetWidthInPixels()
	{
		return values[0].size() * tileSize;
	}

	int Level::GetHeight()
	{
		return values.size();
	}

	int Level::GetHeightInPixels()
	{
		return values.size() * tileSize;
	}

	CollisionType Level::GetCollisionType(int x, int y)
	{
		return values[y][x].colType;
	}

	sf::FloatRect Level::GetBounds(int x, int y)
	{
		return sf::FloatRect(
			(float)x * tileSize, 
			(float)y * tileSize, 
			(float)x * tileSize + tileSize, 
			(float)y * tileSize + tileSize);
	}

	void Level::SetValue(int x, int y, int newVal)
	{
		values[y][x].value = newVal;
	}

	void Level::SetCollisionType(int x, int y, CollisionType colType)
	{
		values[y][x].colType = colType;
	}

	void Level::SetPlayer(Player* player)
	{
		this->player = player;
	}
}